﻿using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace Devonline.Security;

/// <summary>
/// Aes 算法提供加解密的数据安全服务
/// </summary>
public class CertificateSecurityService(SecuritySetting securitySetting) : SecurityService(securitySetting), ICertificateSecurityService, ISecurityService
{
    protected readonly X509Certificate2? _certificate = securitySetting.Certificate;

    /// <summary>
    /// 使用证书加密数据
    /// </summary>
    /// <param name="certificate">加密用的证书</param>
    /// <param name="data">待加密的数据</param>
    /// <returns>加密后的数据</returns>
    public virtual async Task<byte[]> EncryptAsync(X509Certificate2 certificate, byte[] data)
    {
        using var rsa = certificate.GetRSAPublicKey();
        if (rsa is null)
        {
            throw new ArgumentNullException($"Certificate security service encrypt the data use x509 certificate: {certificate.FriendlyName} public key not found!");
        }

        var keyFormatter = new RSAPKCS1KeyExchangeFormatter(rsa);
        var encrypted = keyFormatter.CreateKeyExchange(data, typeof(Aes));
        return await Task.FromResult(encrypted);
    }
    /// <summary>
    /// 使用证书解密数据
    /// </summary>
    /// <param name="certificate">解密用的证书</param>
    /// <param name="data">待解密的数据</param>
    /// <returns>解密后的数据</returns>
    public virtual async Task<byte[]> DecryptAsync(X509Certificate2 certificate, byte[] data)
    {
        using var rsa = certificate.GetRSAPrivateKey();
        if (rsa is null)
        {
            throw new ArgumentNullException($"Certificate security service decrypt the data use x509 certificate: {certificate.FriendlyName} private key not found!");
        }

        var keyFormatter = new RSAPKCS1KeyExchangeDeformatter(rsa);
        var decrypted = keyFormatter.DecryptKeyExchange(data);
        return await Task.FromResult(decrypted);
    }

    /// <summary>
    /// 加密明文数据
    /// </summary>
    /// <param name="data">明文数据</param>
    /// <returns>加密后的数据</returns>
    public override async Task<byte[]> EncryptAsync(byte[] data)
    {
        if (_certificate is null)
        {
            throw new KeyNotFoundException("encrypt certificate not exist!");
        }

        return await EncryptAsync(_certificate, data);
    }
    /// <summary>
    /// 解密密文数据
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public override async Task<byte[]> DecryptAsync(byte[] data)
    {
        if (_certificate is null)
        {
            throw new KeyNotFoundException("decrypt certificate not exist!");
        }

        return await DecryptAsync(_certificate, data);
    }

    /// <summary>
    /// 创建 x.509 证书
    /// </summary>
    /// <param name="info">证书信息</param>
    /// <returns></returns>
    public virtual async Task<X509Certificate2> GenerateAsync(X509CertificateInfo info)
    {
        // 制作 certificate
        using var rsa = RSA.Create(keySizeInBits: info.KeySize);
        var distinguishedName = new X500DistinguishedName($"CN={info.SignatureName}");
        var request = new CertificateRequest(distinguishedName, rsa, info.HashAlgorithmName, info.SignaturePadding);
        request.CertificateExtensions.Add(new X509KeyUsageExtension(info.KeyUsageFlags, info.Critical));
        var certificate = request.CreateSelfSigned(
            notBefore: DateTimeOffset.UtcNow,
            notAfter: DateTimeOffset.UtcNow.AddMonths(info.ExpireTime)
        );

        if (!string.IsNullOrWhiteSpace(info.FilePath))
        {
            var data = certificate.Export(info.ContentType, info.Password);
            await File.WriteAllBytesAsync(info.FilePath, data);
        }

        return certificate;
    }
}